import java.io.DataInput;
import java.io.DataOutput;
import org.apache.hadoop.io.Writable;
import java.io.IOException;
import org.apache.hadoop.io.WritableUtils;
import java.util.*;
import org.apache.hadoop.io.BytesWritable;


public class Edge implements Writable {
  private int beginIndex;     // can't be changed
  private char charIndex;
  private int endIndex;
  private Node startNode;
  private Node endNode;       // can't be changed, could be used as edge id

  public void readFields(DataInput in) throws IOException {
    beginIndex = WritableUtils.readVInt(in);
    charIndex = Character.forDigit(WritableUtils.readVInt(in),10);
    endIndex = WritableUtils.readVInt(in);
    //startNode ok by Edge(Node startNode)
    endNode = new Node();
    endNode.readFields(in);
//    Node node = new Node();
//    node.readFields(in);
//    endNode = node;
  }

  public void write(DataOutput out) throws IOException {
    WritableUtils.writeVInt(out, beginIndex);
    WritableUtils.writeVInt(out, Character.digit(charIndex,10));
    WritableUtils.writeVInt(out, endIndex);
    endNode.write(out);
  }

  public Edge() {
  }
  
  //used for readFields
  public Edge(Node startNode) {
    this.startNode = startNode;
  }
  
  public Edge(int beginIndex, char charIndex, int endIndex, Node startNode, int name) {
    this.beginIndex = beginIndex;
    this.charIndex = charIndex;
    this.endIndex = endIndex;
    this.startNode = startNode;
    this.endNode = new Node(name);
  }

  public Edge(int beginIndex, char charIndex, int endIndex, Node startNode, Node endNode) {
    this.beginIndex = beginIndex;
    this.charIndex = charIndex;
    this.endIndex = endIndex;
    this.startNode = startNode;
    this.endNode = endNode;
  }


//  public Node splitEdge(int index, char newCharIndex, String text, int internalOffset) {//mine, maybe ought to make it one with the one below
  public Node splitEdge(int index, char newCharIndex, int name) {//mine, maybe ought to make it one with the one below
    remove();
    Edge newEdge = new Edge(beginIndex, charIndex, beginIndex+index, startNode, name);
    newEdge.insert();

    beginIndex += index + 1;
    charIndex = newCharIndex;
    startNode = newEdge.getEndNode();
    insert();
    
    return newEdge.getEndNode();
  }

/**
 * Splits an edge into two new edges and returns the intermediate node.
 * This method is called when an implicit node is reached. 
 * @param  suffix A Suffix describing where to split the Edge
 * @return        The intermediate Node connecting the two Edges
 */
  public Node splitEdge(Suffix suffix, char newCharIndex, int name) {
    remove();
    //Edge newEdge = new Edge(beginIndex, beginIndex + suffix.getSpan(), suffix.getOriginNode(), text.substring(0,suffix.getSpan()+1)); //cacao$ a -> [a] - cao, this is relative positions in the array
    Edge newEdge = new Edge(beginIndex, charIndex, beginIndex + suffix.getSpan(), suffix.getOriginNode(), name);
    newEdge.insert(); //the first split of the old Edge

    //newEdge.endNode.setSuffixNode(suffix.getOriginNode());
    beginIndex += suffix.getSpan() + 1;
    charIndex = newCharIndex;
    startNode = newEdge.getEndNode();
    insert(); //the second split of the old Edge
//    System.out.println("dumpedge");
//    dumpEdge();
    return newEdge.getEndNode();
  }

  public void insert() {
    //startNode.addEdge(beginIndex, this);
    startNode.addEdge(this.charIndex, this);
  }

  public void remove() {
    //startNode.removeEdge(beginIndex);
    startNode.removeEdge(this.charIndex);
  }

  public int getSpan() {
    return (endIndex - beginIndex);
  }

  public int getBeginIndex() {
    return beginIndex;
  }
  
  public void incBeginIndex(int inc) {
    this.beginIndex += inc;
  }

  public int getEndIndex() {
    return endIndex;
  }

  public Node getStartNode() {
    return startNode;
  }
  
  public char getCharIndex() {
    return charIndex;
  }

  public void setCharIndex(char c) {
    this.charIndex = c;
  }

  public void setStartNode(Node startNode) {
    this.startNode = startNode;
  }

  public Node getEndNode() {
    return endNode;
  }

/*  public String getText() {
    return text;
  }*/

  public void dumpEdge() {
    System.out.println("bI : " + beginIndex + " eI: " + endIndex + " cI: " + charIndex +" snode: " + startNode + " enode: " + endNode);
  }

  @Override
    public String toString() {
      return endNode.toString();
    }
}
